package com.tdcy.framework.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import com.tdcy.framework.exception.BaseException;

/**
 * 加密解密辅助类.
 */
public abstract class CryptoHUtils {

	/** The Constant CryptogramAlgorithm. */
	private static final String CryptogramAlgorithm = "DESede";

	/** The Constant CryptoTransform. */
	private static final String CryptoTransform = "DESede/CBC/PKCS5Padding";

	/** The Constant CryptogramKEY. */
	private static final byte[] CryptogramKEY = new byte[] { (byte) 218, (byte) 239, (byte) 227, 22, 31, 53, 120, (byte) 224, (byte) 223, (byte) 223, (byte) 171, (byte) 210, (byte) 140, (byte) 158,
			47, 86, 122, 39, (byte) 238, 95, 47, (byte) 138, 44, (byte) 155 };

	/** The Constant CryptogramIV. */
	private static final byte[] CryptogramIV = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };

	/** The Constant _key. */
	private static final SecretKey _key = generateKey(CryptogramKEY);

	/** The Constant _iv. */
	private static final IvParameterSpec _iv = generateIV(CryptogramIV);

	/** The Constant _encryptCache. */
	private static final Map<String, Object> _encryptCache = new ConcurrentHashMap<String, Object>();

	/** The Constant _decryptCache. */
	private static final Map<String, Object> _decryptCache = new ConcurrentHashMap<String, Object>();

	/** The Constant _maxCache. */
	private static final int _maxCache = 5000;

	private static final String UTF8 = "utf-8";

	/**
	 * Instantiates a new crypto helper.
	 */
	private CryptoHUtils() {
	}

	/**
	 * Generate key.
	 * 
	 * @param rgbKey
	 *            the rgb key
	 * 
	 * @return the secret key
	 */
	private static SecretKey generateKey(byte[] rgbKey) {
		try {
			DESedeKeySpec keyspec = new DESedeKeySpec(rgbKey);
			SecretKeyFactory keyfactory = SecretKeyFactory.getInstance(CryptogramAlgorithm);
			SecretKey secretKey = keyfactory.generateSecret(keyspec);
			return secretKey;
		} catch (Exception ex) {
			return null;
		}
	}

	/**
	 * Generate iv.
	 * 
	 * @param rgbIV
	 *            the rgb iv
	 * 
	 * @return the iv parameter spec
	 */
	private static IvParameterSpec generateIV(byte[] rgbIV) {
		try {
			return new IvParameterSpec(rgbIV);
		} catch (Exception ex) {
			return null;
		}
	}

	/**
	 * 加密函数.
	 * 
	 * @param input
	 *            字节数组
	 * 
	 * @return 加密后的字节数组
	 * 
	 * @throws BaseException
	 *             the exception
	 */
	public static byte[] encrypt(byte[] input) throws BaseException {
		try {
			SecureRandom sr = new SecureRandom();
			Cipher cipher = Cipher.getInstance(CryptoTransform);
			cipher.init(Cipher.ENCRYPT_MODE, _key, _iv, sr);
			byte[] result = cipher.doFinal(input);

			return result;
		} catch (Exception ex) {
			throw new BaseException("加密数据出现异常", ex);
		}
	}

	/**
	 * 解密函数.
	 * 
	 * @param input
	 *            需要解密的字节数组
	 * 
	 * @return 解密后的字节数组
	 * 
	 * @throws BaseException
	 *             the exception
	 */
	public static byte[] decrypt(byte[] input) throws BaseException {
		try {
			SecureRandom sr = new SecureRandom();
			Cipher cipher = Cipher.getInstance(CryptoTransform);
			cipher.init(Cipher.DECRYPT_MODE, _key, _iv, sr);
			byte[] result = cipher.doFinal(input);

			return result;
		} catch (Exception ex) {
			throw new BaseException("解密数据出现异常", ex);
		}
	}

	/**
	 * 设置缓存.
	 * 
	 * @param plainText
	 *            明文
	 * @param cipherText
	 *            密文
	 */
	private static void setCache(String plainText, String cipherText) {
		if (!_encryptCache.containsKey(plainText)) {

			if (_encryptCache.size() > _maxCache) {
				_encryptCache.clear();
			}

			_encryptCache.put(plainText, cipherText);

		}

		if (!_decryptCache.containsKey(cipherText)) {

			if (_decryptCache.size() > _maxCache) {
				_decryptCache.clear();
			}

			_decryptCache.put(cipherText, plainText);
		}
	}

	/**
	 * 使用md5编码字节数组.
	 * 
	 * @param data
	 *            the data
	 * 
	 * @return md5编码后的字节数组
	 * 
	 * @throws BaseException
	 *             the exception
	 */
	public static byte[] md5(byte[] data) throws BaseException {
		try {
			return MessageDigest.getInstance("MD5").digest(data);
		} catch (Exception e) {
			throw new BaseException("MD5编码时生成摘要出错", e);
		}
	}

	/**
	 * 使用md5编码字符串(基于hex).
	 * 
	 * @param str
	 *            字符串
	 * 
	 * @return md5编码后的字符串
	 * 
	 * @throws BaseException
	 *             the exception
	 * @throws UnsupportedEncodingException 
	 */
	public static String md5(String str) throws BaseException {
		if (str == null || str.length() == 0) {
			return "";
		}

		return StringUtils.toHexString(md5(str.getBytes()));
	}

	/**
	 * BASE64编码
	 * 
	 * @param src
	 * @return
	 * @throws Exception
	 */
	public static String base64Encoder(String src) throws Exception {
		BASE64Encoder encoder = new BASE64Encoder();
		return encoder.encode(src.getBytes(UTF8));
	}

	/**
	 * BASE64解码
	 * 
	 * @param dest
	 * @return
	 * @throws Exception
	 */
	public static String base64Decoder(String dest) throws Exception {
		BASE64Decoder decoder = new BASE64Decoder();
		return new String(decoder.decodeBuffer(dest), UTF8);
	}

	/**
	 * 字节数组转化为大写16进制字符串
	 * 
	 * @param b
	 * @return
	 */
	private static String byte2HexStr(byte[] b) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < b.length; i++) {
			String s = Integer.toHexString(b[i] & 0xFF);
			if (s.length() == 1) {
				sb.append("0");
			}
			sb.append(s.toUpperCase());
		}
		return sb.toString();
	}
}
